using System.Text;

namespace PopMail
{
    public class POP3MailProcessor
    {
        //Class variables used to manage socket, states and responses
        private POP3Talker pt;
        private POP3Credentials pc;
        //private DBLibrary dbLib;

        public POP3MailProcessor(string host, int port, string userName, string password)
        {
            pt = new POP3Talker(host, port, userName, password);
            pc = pt.Credentials;
            //dbLib = new DBLibrary();
        }

        public delegate bool MailMessageProcessor(POP3MailMessage msg);

        private bool Login()
        {
            POP3ServerResponse response = pt.SendCommand("user" , pc.User);
            bool status = false;
                    
            if (response != null && response.CommandStatus) 
            {
                response = pt.SendCommand("pass" , pc.Password);

                if (response != null && response.CommandStatus)
                {
                    status = true;
                    response.Dispose();
                }
                else
                    status = false;
            }

            return status;
        }

        private bool LogOut()
        {
            POP3ServerResponse response = pt.SendCommand("quit","");
            bool status = response.CommandStatus;

            if (response != null)
                response.Dispose();

            pc = null;
            pt = null;

            return status;
        }

        private int MailCount()
        {
            POP3ServerResponse response = pt.SendCommand("stat","");

            int msgCount = POP3Constants.M_INVALID_MSG_COUNT;

            if (response != null && response.CommandStatus)
            {
                string mailCountDetails = response.ServerResponse.ToString();
                msgCount = int.Parse(mailCountDetails.Split(' ')[1].ToString());
                mailCountDetails = null;
            }

            if (response != null)
                response.Dispose();
            
            return msgCount;
        }

        private bool MarkMailForDeletion(long mailBoxPosition)
        {
            //Mail deletion logic

            POP3ServerResponse response = pt.SendCommand("dele", mailBoxPosition.ToString());
            bool status = response.CommandStatus;

            if (response != null)
                response.Dispose();
            
            return status;

        }

        private POP3MailMessage ParseMail(StringBuilder rawMessage,long mailBoxPosition)
        {
            POP3MailMessage processedMessage = null;
            POP3MimeParser parser = new POP3MimeParser(rawMessage, mailBoxPosition);
            
            processedMessage = parser.ProcessedMessage;
            parser = null;
            
            return processedMessage;
        }

        private POP3MailMessage ReadMail(long mailBoxPosition)
        {
            POP3MailMessage properMessage = null;
            
            //Do the reading bit of the mail here
            POP3ServerResponse response = pt.SendCommand("retr" , mailBoxPosition.ToString());

            if (response.CommandStatus)
            {
                properMessage = ParseMail(response.ServerResponse,mailBoxPosition);
            }

            if (response != null)
                response.Dispose();
            
            return properMessage;

        }

        //private int MessageSignatureExists(string messageSignature)
        //{
        //    ArrayList queryParams = new ArrayList();
            
        //    DBUtilities dbUtilities = new DBUtilities();
        //    queryParams.Add(dbUtilities.CreateSqlParamater("@messageSignature", SqlDbType.NVarChar, 32, ParameterDirection.Input, messageSignature));
            
        //    dbUtilities = null;

        //    return dbLib.ExecuteProcedureScalar("sp_checkSignature_td_InboundEmailRequest", queryParams); 
        //}


        //private bool StoreMessagesToDB(ref POP3MailMessage message)
        //{
        //    bool status = false;
        //    long emailId = 0;
        //    ArrayList outParams = new ArrayList();

        //    if (message.NoOfAttachments > 0)
        //    {
        //        Queue commandQueue = new Queue();

        //        commandQueue.Enqueue(dbLib.GetSqlCommand("sp_insert_td_InboundEmailRequest", message.DbParamList()));

        //        for (int i = 0; i < message.NoOfAttachments; i++)
        //        {
        //            commandQueue.Enqueue(dbLib.GetSqlCommand("sp_insert_td_EmailRequestAttachments", ((POP3MailAttachment)message.Attachments[i]).DbParamList(emailId)));
        //        }

        //        outParams = dbLib.ExecuteQueuedCommandsAL(commandQueue);
                
        //        commandQueue = null;
        //    }
        //    else
        //    {
        //        outParams = dbLib.ExecuteProcedure("sp_insert_td_InboundEmailRequest", message.DbParamList());
        //    }

        //    foreach (SqlParameter param in outParams)
        //    {
        //        if (param.ParameterName == "@insertStatus")
        //            status = bool.Parse(param.Value.ToString());

        //        if (param.ParameterName == "@emailId")
        //            message.EmailId = long.Parse(param.Value.ToString());
        //    }

        //    outParams = null;

        //    return status;
        //}

        private bool SendAcknowledgment(ref POP3MailMessage message)
        {
            bool status = true;
            
            SMTPResponse resp = new SMTPResponse(message.From);
            status = resp.SendMessage();

            resp = null;
            return status;
        }


        private bool AddMessageToWorkQueue(POP3MailMessage message)
        {
            bool status = true;
            //WorkItem wi = new WorkItem();
            //ArrayList outParams = new ArrayList();

            //wi = Utilities.ContentParser.GetWorkItem(message.Body);

            //wi.WorkItemOriginatorId = message.EmailId;
            //wi.WorkItemType = WorkQueueConstantValues.M_WI_TYPE_EMAIL;
            //wi.ResponseRecepient = message.From;

            //outParams = dbLib.ExecuteProcedure("sp_insert_td_WorkItem", wi.DbParamList());

            //foreach (SqlParameter param in outParams)
            //{
            //    if (param.ParameterName == "@insertStatus")
            //        status = bool.Parse(param.Value.ToString());
            //}
            
            return status;
        }

        public bool ProcessMails(MailMessageProcessor processor)
        {
            bool status = true;

            status = Login();

            if (status == false)
            {
                return status;
                //Log error message that login failed
            }
            
            int mailCount = MailCount();

            if (mailCount == POP3Constants.M_INVALID_MSG_COUNT)
            {
                return status;
                //Log error message that unable to retreive message count
            }

            for (long i = mailCount; i >= 1; i--)
            {
                POP3MailMessage currMessage = new POP3MailMessage();
                //int noOfemailsWithThisSignature ;
    
                currMessage =  ReadMail(i);
                //noOfemailsWithThisSignature = MessageSignatureExists(currMessage.MessageSignature);

                //if (noOfemailsWithThisSignature == -1)
                //    Log error;

                //if (noOfemailsWithThisSignature == 0)
                //{
                //    status = StoreMessagesToDB(ref currMessage);

                //    if (status)
                //        status = SendAcknowledgment(ref currMessage);
                //    else
                //        return status;

                //    if (status)
                //        status = AddMessageToWorkQueue(currMessage);
                //    else
                //        return status;
                    
                //}

                // Call the delegate Message Processor
                status = processor(currMessage);

                // If the processor returns true , that means it successfully processed the message andthe msg can now be deleted
                if (status)
                {
                    status = MarkMailForDeletion(currMessage.InboxPosition);
                }

                //if (status)
                //    continue;
                //else
                //    return status;
            }

            return LogOut();
        }

    }
}
